package app.keter.secruity;

import app.keter.secruity.encoder.SHAEncoder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;

@SuppressWarnings("SpringJavaAutowiringInspection")
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter{

    @Autowired
    private JwtAuthenticationEntryPoint unauthorizedHandler;

    @Autowired
    private UserDetailsService userDetailsService;

    @Autowired
    public void configureAuthentication(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception {
        authenticationManagerBuilder
                .userDetailsService(this.userDetailsService)
                .passwordEncoder(passwordEncoder());
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new SHAEncoder();
    }

    @Bean
    public JwtAuthenticationTokenFilter authenticationTokenFilterBean() throws Exception {
        return new JwtAuthenticationTokenFilter();
    }

    public static final String LOGIN_PAGE = "/ajax/login"; //登录页
    public static final String LOGIN_ENTRY_POINT = "/authenticate";//登录认证请求

    @Override
    protected void configure(HttpSecurity httpSecurity) throws Exception {
        //管理员
        httpSecurity.authorizeRequests().antMatchers("/admin/**").hasRole("ADMIN");
        //普通用户
        httpSecurity.authorizeRequests().antMatchers(
                "/tokenrefresh"
                ,"/user/**"
        ).hasAnyRole("ADMIN","USER");

        httpSecurity
                // 由于使用的是JWT，我们这里不需要csrf
                .csrf().disable()
                .cors() //配合CorsConfig完成跨域认证的支持
                .and()
                .exceptionHandling().authenticationEntryPoint(unauthorizedHandler).and()

                // 基于token，所以不需要session
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()

                .authorizeRequests()
                //.antMatchers(HttpMethod.OPTIONS, "/**").permitAll()

                // 允许对于网站静态资源的无授权访问
                .antMatchers(
                        "/static/**"
                        ,"/css/**"
                        ,"/venders/**"
                        ,"/lib/**"
                        ,"/public/**"
                        ,"/**/*.js"
                        ,"/**/*.css"
                ).permitAll()
                // 对于获取token的rest api要允许匿名访问
                .antMatchers(LOGIN_ENTRY_POINT).permitAll()
                //登录页面和注销
                .antMatchers(LOGIN_PAGE,"/logout").permitAll()
                //所有页面放开权限
                .antMatchers("/ajax/home").permitAll()
                // 除上面外的所有请求全部需要鉴权认证
                .anyRequest().authenticated()
                .and()
                //注销由客户端实现：删除token即可
                .logout().logoutRequestMatcher(new AntPathRequestMatcher("/logout")).logoutSuccessUrl(LOGIN_PAGE)
               ;


        // 添加JWT filter
        httpSecurity
                .addFilterBefore(authenticationTokenFilterBean(), UsernamePasswordAuthenticationFilter.class);

        // 禁用缓存
        httpSecurity.headers().cacheControl();
    }
}
